

package com.xgit.iov.common.log.util;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import com.xgit.iov.common.core.constant.CommonConstants;
import com.xgit.iov.common.core.entity.SysLog;
import com.xgit.iov.common.log.annotation.LogAnnotation;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 系统日志工具类
 *
 * @author william
 */
@UtilityClass
public class SysLogUtils {

	public SysLog getSysLog(JoinPoint joinPoint, final Exception e) {

		// 获得注解
		LogAnnotation controllerLog = getAnnotationLog(joinPoint);
		if (controllerLog == null) {
			return null;
		}

		HttpServletRequest request = ((ServletRequestAttributes) Objects
			.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
		SysLog sysLog = new SysLog();
		sysLog.setCreateBy(Objects.requireNonNull(getUsername()));
		sysLog.setType(CommonConstants.STATUS_NORMAL);
		sysLog.setRemoteAddr(ServletUtil.getClientIP(request));
		sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI()));
		sysLog.setRequestMethod(request.getMethod());
		sysLog.setUserAgent(request.getHeader("user-agent"));
		sysLog.setServiceId(getClientId());
		// 设置方法名称
		String className = joinPoint.getTarget().getClass().getName();
		String methodName = joinPoint.getSignature().getName();
		sysLog.setMethod(className + "." + methodName + "()");

		if (ObjectUtil.isNotEmpty(e)) {
			sysLog.setType(CommonConstants.STATUS_DEL);
			sysLog.setException(StringUtils.substring(e.getMessage(), 0, 2000));
		}

		getMethodDescription(joinPoint, controllerLog, sysLog);

		sysLog.setCreateTime(LocalDateTime.now());

		return sysLog;
	}

	/**
	 * 获取客户端
	 *
	 * @return clientId
	 */
	private String getClientId() {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication instanceof OAuth2Authentication) {
			OAuth2Authentication auth2Authentication = (OAuth2Authentication) authentication;
			return auth2Authentication.getOAuth2Request().getClientId();
		}
		return null;
	}

	/**
	 * 获取用户名称
	 *
	 * @return username
	 */
	private String getUsername() {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication == null) {
			return null;
		}
		return authentication.getName();
	}

	/**
	 * 获取注解中方法的描述信息
	 * @throws Exception
	 */
	public void getMethodDescription(JoinPoint joinPoint, LogAnnotation log, SysLog sysLog) {

		// 设置标题
		sysLog.setTitle(log.value());
		// 设置模块名
//		sysLog.setModule(log.value());
		// 是否需要保存request，参数和值
		if (log.recordRequestParam()) {
			// 获取参数的信息，传入到数据库中。
			setRequestValue(joinPoint, sysLog);
		}
	}

	/**
	 * 获取请求的参数
	 *
	 * @param sysLog 操作日志
	 * @throws Exception 异常
	 */
	private void setRequestValue(JoinPoint joinPoint, SysLog sysLog) {
		String requestMethod = sysLog.getRequestMethod();
		if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
			String params = argsArrayToString(joinPoint.getArgs());
			sysLog.setParams(StringUtils.substring(params, 0, 2000));
		} else {

			List<Object> httpReqArgs = new ArrayList<Object>();
			Object[] args = joinPoint.getArgs();// 参数值
			String params = null ;
			for (Object object : args) {
				httpReqArgs.add(object);
			}
			params = JSONUtil.toJsonStr(httpReqArgs);
			if (StrUtil.isNotEmpty(params)){
				sysLog.setParams(StringUtils.substring(params, 0, 2000));
			}


		}
	}

	/**
	 * 是否存在注解，如果存在就获取
	 */
	private LogAnnotation getAnnotationLog(JoinPoint joinPoint) {
		Signature signature = joinPoint.getSignature();
		MethodSignature methodSignature = (MethodSignature) signature;
		Method method = methodSignature.getMethod();

		if (method != null) {
			return method.getAnnotation(LogAnnotation.class);
		}
		return null;
	}

	/**
	 * 参数拼装
	 */
	private String argsArrayToString(Object[] paramsArray) {
		String params = "";
		if (paramsArray != null && paramsArray.length > 0) {
			for (int i = 0; i < paramsArray.length; i++) {
				if (!isFilterObject(paramsArray[i])) {
					Object jsonObj = JSONUtil.toJsonStr(paramsArray[i]);
					if (ObjectUtil.isNotEmpty(jsonObj)){
						params += jsonObj.toString() + " ";
					}

				}
			}
		}
		return params.trim();
	}

	/**
	 * 判断是否需要过滤的对象。
	 *
	 * @param o 对象信息。
	 * @return 如果是需要过滤的对象，则返回true；否则返回false。
	 */
	public boolean isFilterObject(final Object o) {
		return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
	}



}
